<template>
  <!-- 全屏扫描二维码组件 暂不支持扫描一维码 需配置https协议 -->
  <div class="fullscreen" v-if="scanVisible">
    <qrcode-stream v-show="scanCode" :camera="camera" :torch="torchActive" :track="undefined" @init="onInit" @decode="onDecode">
      <div v-if="showTip">
        <div class="qr-scanner">
          <div class="box">
            <div class="line"></div>
            <div class="angle"></div>
          </div>
          <div class="scan-txt">
            将二维码放入框内，即自动扫描
          </div>
        </div>
        <div class="operation">
          <van-row type="flex" justify="space-between">
            <van-col :span="6">
              <div class="back" @click="cancelScan">
                <div class="img-box">
                  <img src="../../assets/images/back.png" alt="">
                </div>
                <div class="txt-box">
                  <p>取消扫码</p>
                </div>
              </div>
            </van-col>
            <van-col :span="6">
              <div class="select-img" @click="selectImg">
                <div class="img-box">
                  <img src="../../assets/images/img.png" alt="">
                </div>
                <div class="txt-box">
                  <p>选择图片</p>
                </div>
              </div>
            </van-col>
          </van-row>
        </div>
      </div>
    </qrcode-stream>
    <van-popup v-model="showPopup" position="bottom" @closed="closePopup" :close-on-click-overlay="false" closeable>
      <div class="title">选择图片</div>
      <qrcode-capture class="capture" id="capture" v-show="captureCode" @decode="onDecode" :multiple="false" :capture="capture.value" @detect="onDetect" />
    </van-popup>
  </div>
</template>

<script>
import { Col, Popup, Row } from 'vant';
import { QrcodeStream, QrcodeCapture } from 'vue-qrcode-reader';
export default {
  // 注册
  components: {
    QrcodeStream,
    QrcodeCapture,
    [Row.name]: Row,
    [Col.name]: Col,
    [Popup.name]: Popup,
  },
  props: {
    scanVisible: {
      type: Boolean,
      default: false,
    },
    // 摄像头类型
    camera: {
      type: String,
      default: 'auto', // auto: 自动获取 / rear: 前置摄像头 / front: 后置摄像头 / off: 关闭摄像头
    },
    // 是否开启闪光灯
    torchActive: {
      type: Boolean,
      default: false,
    },
    // 图片上传方式
    capture: {
      type: Object,
      default: () => {
        var obj = { value: false }
        return obj;
      },
    },
    // 扫码成功回调函数
    propFunc: {
      type: Function,
      default: () => { },
    },
    // 成功提示
    scanSuccTip: {
      type: String,
      default: '扫码成功！',
    },
    // 错误提示
    scanErrTip: {
      type: String,
      default: '扫码失败，请重试',
    }
  },
  data() {
    return {
      scanCode: false,
      showTip: false,
      captureCode: false,
      showPopup: false,
    };
  },
  methods: {
    // 初始化扫码
    async onInit(promise) {
      try {
        let { capabilities } = await promise;
        if (capabilities.deviceId) {
          this.scanCode = true;
          this.showTip = true;
        }
      } catch (error) {
        var scanError = '';
        switch (error.name) {
          case 'NotAllowedError':
            scanError = 'ERROR: 您需要授予相机访问权限';
            break;
          case 'NotFoundError':
            scanError = 'ERROR: 这个设备上没有摄像头';
            break;
          case 'NotSupportedError':
            scanError = 'ERROR: 所需的安全上下文(HTTPS、本地主机)';
            break;
          case 'NotReadableError':
            scanError = 'ERROR: 相机被占用';
            break;
          case 'OverconstrainedError':
            scanError = 'ERROR: 安装摄像头不合适';
            break;
          case 'StreamApiNotSupportedError':
            scanError = 'ERROR: 此浏览器不支持 stream API';
            break;
          case 'InsecureContextError':
            scanError = 'ERROR: 仅允许在安全环境下访问摄像头。请使用 HTTPS 或 localhost，而不是 HTTP。';
            break;
          default:
            scanError = 'ERROR: 未知错误';
            break;
        }
        this.$Tols.tip(scanError, 1500);
        this.cancelScan();
      }
    },
    /**
     * @param { Object } imageData 图片数据 或 null
     * @param { String } content   解码结果 或 null
     * @param { Object } location  二维码坐标数据 或 null
     * 直接扫描图像 并返回一个包含 imageData & content & location 的 promise
     * 如果没有 QRCode 或者发生错误 detect会静默失败 返回的promise为空 */
    async onDetect(promise) {
      try {
        let { content } = await promise;
        if (!content) {
          this.$Tols.tip(this.scanErrTip, 1000)
        }
      } catch (err) {
        console.log('onDetect error is ', err)
      }
    },
    // 解码
    onDecode(result) {
      if (result && this.propFunc) {
        this.$Tols.tip(this.scanSuccTip, 1000, () => {
          this.cancelScan();
          this.propFunc(result);
        })
      } else {
        this.$Tols.tip(this.scanErrTip, 1000)
      }
    },
    // 取消扫码
    cancelScan() {
      this.showTip = false;
      this.scanCode = false;
      this.showPopup = false
      this.captureCode = false;
      this.$emit('update:scanVisible', false);
    },
    // 选择图片
    selectImg() {
      this.showPopup = true;
      this.captureCode = true;
    },

    // 关闭弹出层
    closePopup() {
      this.showPopup = false;
      this.captureCode = false;
    }
  },
};
</script>
<style lang="scss" scoped>
.fullscreen {
  position: fixed;
  z-index: 1000;
  top: 0;
  bottom: 0;
  right: 0;
  left: 0;
}

.qr-scanner {
  width: 100%;
  height: 100vh;
  position: relative;
  background-color: rgba(17, 17, 17, 0);

  // 扫描框
  .box {
    height: 100%;
    width: 100%;
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    overflow: hidden;

    .line {
      height: 120%;
      width: 100%;
      background: linear-gradient(
        180deg,
        rgba(0, 255, 51, 0) 43%,
        #00ff33 211%
      );
      transform: translateY(-100%);
      animation: radar-beam 2s infinite alternate;
      animation-timing-function: cubic-bezier(0.53, 0, 0.43, 0.99);
      animation-delay: 1.4s;
    }
  }

  // 提示文字
  .scan-txt {
    width: 100%;
    height: 35px;
    line-height: 35px;
    font-size: 14px;
    text-align: center;
    margin: 0 auto;
    position: absolute;
    top: 60%;
    left: 0;
    color: #fff;
  }
}

.operation {
  position: absolute;
  bottom: 0;
  left: 0;
  padding: 20px 5% 15px 5%;
  width: 100%;
  height: 100px;
  background-color: rgba($color: #333, $alpha: 0.3);

  .back,
  .select-img {
    color: #fff;
    // width: 50%;
    text-align: center;

    .img-box {
      width: 45px;
      height: 45px;
      background-color: rgba($color: #333, $alpha: 0.6);
      border-radius: 50%;
      display: flex;
      text-align: center;
      justify-content: center;
      margin: auto;

      img {
        width: 45px;
        height: 45px;
        padding: 10px;
      }
    }

    .txt-box {
      font-size: 15px;
      line-height: 30px;
    }
  }

  .capture {
    font-size: 16px;
  }
}

.van-popup {
  background-color: #fff !important;
  height: 30%;

  .title {
    text-align: center;
    font-size: 18px;
    font-weight: bold;
    line-height: 30px;
    height: 10%;
    margin-top: 10px;
  }

  .capture {
    z-index: 2004;
    padding: 40px 20px;
    font-size: 16px;
  }
}

@keyframes radar-beam {
  0% {
    transform: translateY(-100%);
  }

  100% {
    transform: translateY(0);
  }
}
</style>